Spring ContextLoaderListener 启动流程解析二

本篇博客主要讲的 spring 如何初始化其上下文的源码简单解读。

上次我们讲到了 AbstractApplicationContext.refresh() 这个方法。

    public void refresh() throws BeansException, IllegalStateException {
        synchronized(this.startupShutdownMonitor) {
            //容器刷新前准备工作
            this.prepareRefresh();
            //启动 obtainFreshBeanFactory 里的 refreshBeanFactory() 方法
            //主要是把旧的 beanFactory 关闭,重新创建一个 beanFactory
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
            this.prepareBeanFactory(beanFactory);

            ...

接下来讲解 BeanFactory 是如何创建的。可以看到 beanFactory 是通过 obtainFreshBeanFactory() 这个方法创建的。

AbstractApplicationContext.obtainFreshBeanFactory

    protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
        //把旧的 beanFactory 关闭,重新创建一个 beanFactory
        this.refreshBeanFactory();
        ConfigurableListableBeanFactory beanFactory = this.getBeanFactory();
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Bean factory for " + this.getDisplayName() + ": " + beanFactory);
        }

        return beanFactory;
    }

AbstractRefreshableApplicationContext.refreshBeanFactory

    protected final void refreshBeanFactory() throws BeansException {
        //删除旧的 beanFactory
        if (this.hasBeanFactory()) {
            this.destroyBeans();
            this.closeBeanFactory();
        }

        try {
            DefaultListableBeanFactory beanFactory = this.createBeanFactory();
            beanFactory.setSerializationId(this.getId());
            //用户自定义 beanFactory,不做赘述
            this.customizeBeanFactory(beanFactory);
            //加载用户的 bean 配置文件
            this.loadBeanDefinitions(beanFactory);
            synchronized(this.beanFactoryMonitor) {
                this.beanFactory = beanFactory;
            }
        } catch (IOException var5) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), var5);
        }
    }

XmlWebApplicationContext.loadBeanDefinitions

参考 https://www.imooc.com/article/13900

loadBeanDefinitions 的主要工作就是获取配置,解析配置,得到 xml Document 对象,然后继续进行下面的解析:

DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions

    protected void doRegisterBeanDefinitions(Element root) {
        String profileSpec = root.getAttribute("profile");
        if (StringUtils.hasText(profileSpec)) {
            Assert.state(this.environment != null, "Environment must be set for evaluating profiles");
            String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, ",; ");
            if (!this.environment.acceptsProfiles(specifiedProfiles)) {
                return;
            }
        }

        BeanDefinitionParserDelegate parent = this.delegate;
        this.delegate = this.createHelper(this.readerContext, root, parent);
        this.preProcessXml(root);
        //主要看这个方法
        this.parseBeanDefinitions(root, this.delegate);
        this.postProcessXml(root);
        this.delegate = parent;
    }

DefaultBeanDefinitionDocumentReader.parseBeanDefinitions

参考 https://www.imooc.com/article/13901

parseBeanDefinitions 判断当前解析元素是否属于默认的命名空间,如果是的话,就调用 parseDefaultElement() 方法,否则调用 delegate.parseCustomElement() 方法。

    protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
        if (delegate.isDefaultNamespace(root)) {
            NodeList nl = root.getChildNodes();

            for(int i = 0; i < nl.getLength(); ++i) {
                Node node = nl.item(i);
                if (node instanceof Element) {
                    Element ele = (Element)node;
                    if (delegate.isDefaultNamespace(ele)) {
                        //当前解析元素属于默认的命名空间,解析 spring 默认的标签,如 <bean/> 这些
                        this.parseDefaultElement(ele, delegate);
                    } else {
                        delegate.parseCustomElement(ele);
                    }
                }
            }
        } else {
            delegate.parseCustomElement(root);
        }

    }

DefaultBeanDefinitionDocumentReader.parseDefaultElement

parseDefaultElement 根据不同的标签元素,调用不同的解析注册方法

    private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
        if (delegate.nodeNameEquals(ele, "import")) {
            this.importBeanDefinitionResource(ele);
        } else if (delegate.nodeNameEquals(ele, "alias")) {
            this.processAliasRegistration(ele);
        } else if (delegate.nodeNameEquals(ele, "bean")) {
            this.processBeanDefinition(ele, delegate);
        } else if (delegate.nodeNameEquals(ele, "beans")) {
            this.doRegisterBeanDefinitions(ele);
        }

    }

一步步跟进,除了 processAliasRegistration 其余方法最终都是 bean 的注册: DefaultListableBeanFactory.registerBeanDefinition

DefaultListableBeanFactory.registerBeanDefinition

    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {
        Assert.hasText(beanName, "Bean name must not be empty");
        Assert.notNull(beanDefinition, "BeanDefinition must not be null");
        if (beanDefinition instanceof AbstractBeanDefinition) {
            try {
                ((AbstractBeanDefinition)beanDefinition).validate();
            } catch (BeanDefinitionValidationException var7) {
                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", var7);
            }
        }

        synchronized(this.beanDefinitionMap) {
            Object oldBeanDefinition = this.beanDefinitionMap.get(beanName);
            if (oldBeanDefinition != null) {
                if (!this.allowBeanDefinitionOverriding) {
                    throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName + "': There is already [" + oldBeanDefinition + "] bound.");
                }

                if (this.logger.isInfoEnabled()) {
                    this.logger.info("Overriding bean definition for bean '" + beanName + "': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
                }
            } else {
                //添加到 list
                this.beanDefinitionNames.add(beanName);
                this.frozenBeanDefinitionNames = null;
            }
            //把 BeanDefinition 放到 map 中,到此注册就完成了。
            //在后面实例化的时候,就是把 beanDefinitionMap 中的 BeanDefinition 取出来,逐一实例化
            this.beanDefinitionMap.put(beanName, beanDefinition);
        }

        this.resetBeanDefinition(beanName);
    }

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 rockeycui@163.com

文章标题:Spring ContextLoaderListener 启动流程解析二

文章字数:773

本文作者:崔石磊(RockeyCui)

发布时间:2018-09-30, 19:00:00

原始链接:https://cuishilei.com/Spring ContextLoaderListener 启动流程解析二.html

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

目录
×

喜欢就点赞,疼爱就打赏